package org.easy.file.monitor;

import cn.hutool.core.thread.NamedThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.easy.file.manager.ITaskManager;
import org.easy.file.manager.TaskManager;
import org.easy.file.model.FileModel;
import org.easy.tool.consts.EasyConstants;
import org.easy.tool.io.FileUtil;
import org.easy.tool.pool.ThreadPoolManager;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @Description: 文件工厂类
 * @Author: wxl
 * @CreateTime: 2022/12/27 14:50
 */
@Slf4j
public class FileFactory {

    private List<String> paths;

    private Map<String,String> taskData;

    private final ITaskManager taskManager;

    private final ThreadPoolExecutor executor;

    private FileFactory ()  {
        this.taskManager = new TaskManager();
        // 给一个默认值
        this.executor = ThreadPoolManager.create(2);
        NamedThreadFactory namedThreadFactory = new NamedThreadFactory("task-pool-file-",true);
        this.executor.setThreadFactory(namedThreadFactory);
        this.readFileFromResource();
    }

    private FileFactory (String path) {
        this(Collections.singletonList(path));
    }

    private FileFactory (List<String> paths) {
        this();
        this.paths = paths;
        this.reSetPoolSize(this.paths.size());
    }

    public List<String> getPaths() {
        return paths;
    }

    public void setPaths (String path) {
        if ( null == getPaths()) {
            this.paths = new ArrayList<>();
        }
        this.paths.add(path);
        this.reSetPoolSize(this.paths.size());
    }

    public ITaskManager getTaskManager() {
        return taskManager;
    }

    public ThreadPoolExecutor getExecutor() {
        return executor;
    }

    public void startTask(String filePath){
        setPaths(filePath);
        this.getExecutor().execute(() -> this.runTask0(filePath));
    }

    public boolean stopTask0 (String filePath) {
        List<FileModel> fileModels = getFileTasks();
        if (fileModels.isEmpty()) {
            return Boolean.FALSE;
        }
        Optional<FileModel> optional = fileModels.stream().filter(f -> filePath.equals(f.getFilePath())).findAny();
        if (optional.isPresent()) {
            Future<Boolean> future = this.getExecutor().submit(() -> {
                FileModel fileModel = optional.get();
                ITask iTask = this.getTaskManager().getTask(fileModel.getTaskId());
                iTask.setRunning(false);
                boolean stopFlag = iTask.stop();
                if (stopFlag) {
                    // 删除任务
                    delToFile(iTask);
                    this.getTaskManager().delTask(fileModel.getTaskId());
                }
                return stopFlag;
            });
            try {
                return future.get();
            } catch (Exception e) {
                return Boolean.FALSE;
            }
        } else {
            return Boolean.FALSE;
        }
    }

    public List<FileModel> getFileTasks(){
        return this.getTaskManager().getFileTaskList();
    }

    private void runTask0(String path) {
        if (!getTaskData().isEmpty()) {
            Optional<FileModel> optional = getTaskData().values().stream()
                    .map(FileModel::stringToModel)
                    .filter(f -> path.equals(f.getFilePath()))
                    .findAny();
            if (optional.isPresent()) {
                FileModel model = optional.get();
                if (model.isRunning()) {
                    log.info("监控路径["+path+"]任务已经启动，无需重新启动!");
                } else {
                    runTask(model);
                }
            } else {
                runTask(path);
            }
        } else {
            runTask(path);
        }
    }

    private void runTask(FileModel model){
        ITask iTask = model.stringToTask();
        runTask(iTask);
    }

    private void runTask(ITask iTask){
        iTask.setRunning(true);
        boolean startFlag = iTask.runTask();
        if (startFlag) {
            appendToFile(iTask);
            String taskId = iTask.getTaskId();
            this.getTaskManager().addTask(taskId,iTask);
        }
    }

    private void runTask(String path){
        ITask iTask = FileTask.create(path);
        runTask(iTask);
    }

    /**
     * 将任务文件上的任务进行开启.........
     */
    private void readFileFromResource() {
        Map<String,String> data = FileUtil.readAsStringFromResource(EasyConstants.TASK_FILE_NAME);
        setTaskData(data);
        // 对任务进行实现
        if (!getTaskData().isEmpty()) {
            getTaskData().values().stream().map(FileModel::stringToModel).forEach(f -> {
                if (f.isRunning()) {
                    runTask(f);
                }
            });
        }
    }

    /**
     * 向任务文件追加
     * @param iTask 任务
     */
    private void appendToFile (ITask iTask) {
        FileModel fileModel = new FileModel(iTask);
        String str = fileModel.toString();
        log.info("需要添加到任务文件的数据:{}",str);
        if (!taskData.isEmpty()) {
            List<FileModel> fileModels = taskData.values().stream().map(FileModel::stringToModel).collect(Collectors.toList());
            fileModels.removeIf(model -> model.getTaskId().equals(fileModel.getTaskId()));
            fileModels.add(fileModel);
            setTaskData(fileModels);
        } else {
            Map<String,String> dataS = fileModel.fileToMap();
            setTaskData(dataS);
        }
        // 向文件写入
        FileUtil.writeToFileFromResource(getTaskData());
    }

    private void delToFile(ITask iTask){
        FileModel fileModel = new FileModel(iTask);
        String str = fileModel.toString();
        log.info("需要删除到任务文件的数据:{}",str);
        if (!taskData.isEmpty()) {
            List<FileModel> fileModels = taskData.values().stream().map(FileModel::stringToModel).collect(Collectors.toList());
            fileModels.removeIf(model -> model.getTaskId().equals(fileModel.getTaskId()));
            setTaskData(fileModels);
        }
        // 向文件写入
        FileUtil.writeToFileFromResource(getTaskData());
    }

    private void setTaskData(List<FileModel> fileModels){
        Map<String,String> tasks = new ConcurrentHashMap<>(1 << 8);
        for (FileModel model : fileModels) {
            tasks.put(model.getTaskId() ,model.toString());
        }
        // 更新
        setTaskData(tasks);
    }

    public void reSetPoolSize(int size){
        int corePoolSize = size + 1;
        int maxPoolSize  = size * 2 + 1;
        this.getExecutor().setCorePoolSize(corePoolSize);
        this.getExecutor().setMaximumPoolSize(maxPoolSize);
    }

    public Map<String,String> getTaskData() {
        return taskData;
    }

    public void setTaskData(Map<String,String> taskData) {
        this.taskData = taskData;
    }

    public static FileFactory create () {
        return new FileFactory();
    }

}
